#include <sstream>
#include "module.h"
#include "log.h"
#include "config.h"
#include "env.h"
#include "library.h"

namespace qtch {

static ConfigVar<std::string>::ptr g_module_path = Config::LookUp("module.path",std::string("module"), "module path");

static Logger::ptr logger = QTCH_LOG_NAME("system");

Module::Module(const std::string& name,const std::string& version,const std::string& desc) 
    :m_name(name)
    ,m_version(version)
    ,m_desc(desc){
}

void Module::onBeforeArgsParse(int argc,char** argv) {
}

void Module::onAfterArgsParse(int argc,char** argv) {
}

bool Module::onLoad() {
    return true;
}

bool Module::onUnload() {
    return true;
}

bool Module::onServerReady() {
    return true;
}

bool Module::onServerUp() {
    return true;
}

std::string Module::statusString() {
    std::stringstream ss;
    ss << "[ Module name=" << m_name
       << ", version=" << m_version
       << ",desc=" << m_desc
       << ", fileName=" << m_fileName << " ]";
    return ss.str();
}

ModuleManager::ModuleManager() {
}

void ModuleManager::add(Module::ptr m) {
    del(m->getName());
    RWMutexType::WriteLock lock(m_mutex);
    m_modules[m->getName()] = m;

}

void ModuleManager::del(const std::string& name) {
    Module::ptr moduler;
    {
        RWMutexType::WriteLock lock(m_mutex);
        auto it = m_modules.find(name);
        if(it==m_modules.end()){
            return;
        }
        moduler = it->second;
        m_modules.erase(it);
    }
    moduler->onUnload();
}

void ModuleManager::delAll() {
    RWMutexType::ReadLock lock(m_mutex);
    auto tmp = m_modules;
    lock.unlock();
    for(auto& i:tmp){
        del(i.first);
    }
}

void ModuleManager::init() {
    auto path = EnvMgr::GetInstance()->getAbsolutePath(g_module_path->getValue());
    std::vector<std::string> files;
    FSUtil::listAllFiles(files,path,".so");
    std::sort(files.begin(),files.end());
    for(auto & i : files){
        InitModule(i);
    }
}

Module::ptr ModuleManager::get(const std::string& name) {
    RWMutexType::ReadLock lock(m_mutex);
    auto it = m_modules.find(name);
    return it == m_modules.end() ? nullptr : it->second;
}

void ModuleManager::listAll(std::vector<Module::ptr>& m) {
    RWMutexType::ReadLock lock(m_mutex);
    for(auto& i:m_modules){
        m.push_back(i.second);
    }
}

void ModuleManager::foreach(std::function<void(Module::ptr)> cb) {
    std::vector<Module::ptr> ms;
    listAll(ms);
    for(size_t i = 0; i < ms.size(); ++i){
        cb(ms[i]);
    }
}

void ModuleManager::InitModule(const std::string& path) {
    Module::ptr m = Library::LoadModule(path);
    if(m){
        add(m);
    }
}



}